#include <assert.h>
#include <stdio.h>

#include <dinfra.h>

#include <dinfra/mplf/tstack.h>

#include <page_alloc.h>
#include <stdlib.h>

static inline void *a_radix_alloc(size_t size){
	// printf("malloc %lu\n", rdx_nr * sizeof(radix_t));
	return aligned_alloc(4096, size);
}

/* 单级 */
DEF_RADIX_FIND_COMP(flat, 9, id_val_decoder, id_val_encoder, id_radix_alloc)
APPEND_RADIX_FIND_COMP(flat, id)

/* 多级 */
DEF_RADIX_FIND_COMP(l1create, 9, id_val_decoder, id_val_encoder, a_radix_alloc)
DEF_RADIX_FIND_COMP(l2create, 9, id_val_decoder, id_val_encoder, a_radix_alloc)
DEF_RADIX_FIND_COMP(l3create, 9, id_val_decoder, id_val_encoder, a_radix_alloc)
DEF_RADIX_FIND_COMP(l4create, 9, id_val_decoder, id_val_encoder, a_radix_alloc)

// APPEND_RADIX_FIND_COMP(l4create, id);
// APPEND_RADIX_FIND_COMP(l3create, l4create);
// APPEND_RADIX_FIND_COMP(l2create, l3create);
// APPEND_RADIX_FIND_COMP(l1create, l2create);

DEF_RADIX_FIND(p4, l1create, l2create, l3create, l4create)

// MAPL(APPEND_RADIX_FIND_COMP, GEN_PAIRLIST(l1create, l2create, l3create, l4create, id));

/* 如何快速连接 */

// #define __IDRADIX(bit, name)	DEF_RADIX_FIND_COMP( name##_##bit , bit, id_val_decoder, id_val_encoder, a_radix_alloc)
// #define IDRADIX(bit)			__IDRADIX(bit, testbit)

// /* 需要生成 */


// MAP(IDRADIX, 9, 9, 9, 9)





void test_radix(){
	radix_t tmp[512] = {0};
	tmp[5] = (radix_t)1;

	radix_t *prdx;

	radix_t res = flat_radix_find(tmp, &prdx, 5);
	assert(res == (radix_t)1);

	assert(prdx == &tmp[5]);
	res = l1create_radix_find(tmp, &prdx, 0xDEADBEEFABCDEEEF >> 12);
	assert(res == NULL);
	*prdx = (radix_t)0xDEADBEEFABCD;
	res = l1create_radix_find(tmp, &prdx, 0xDEADBEEFABCDEEEF >> 12);
	assert(res == (radix_t)0xDEADBEEFABCD);
	res = p4_radix_find(tmp, &prdx, 0xDEADBEEFABCDEEEF >> 12);
	assert(res == (radix_t)0xDEADBEEFABCD);
}

DEF_SLIST_HEAD(test_slist);
DEF_SLIST_HEAD(test_slist1);
DEF_DLIST_HEAD(test_dlist);
/* 测试链表 */
void test_list(){
	/* slist */
	slist_t **a = (slist_t **)malloc(sizeof(slist_t *) * 128);
	assert(a);
	for(word_t idx = 0; idx < 128; idx++){
		a[idx] = (slist_t *)malloc(sizeof(slist_t));
		if(a[idx]) slist_push(&test_slist, a[idx]);
	}
	assert(test_slist.next == a[127]);
	word_t cnt = 0;
	for(slist_t *node = test_slist.next; node != &test_slist; node = node->next){
		cnt++;
	}
	assert(cnt == 128);
	slist_append(&test_slist1, a[127], a[0]);
	assert(test_slist1.next == a[127]);

	for(word_t idx = 0; idx < 64; idx++){
		slist_t *tmp = slist_pop(&test_slist1);
		assert(tmp == a[127-idx]);
		free(tmp);
	}

	cnt = 0;
	for(slist_t *node = test_slist1.next; node != &test_slist1; node = node->next){
		cnt++;
	}
	assert(cnt == 64);

	/* dlist */
	dlist_t **b = (dlist_t **)malloc(sizeof(dlist_t *) * 256);
	assert(b);
	for(word_t idx = 0; idx < 128; idx++){
		b[idx] = (dlist_t *)malloc(sizeof(dlist_t));
		if(b[idx]) dlist_add_head(&test_dlist, b[idx]);
	}
	assert(test_dlist.next == b[127]);
	cnt = 0;
	for(dlist_t *node = test_dlist.next; node != &test_dlist; node = node->next){
		cnt++;
	}
	assert(cnt == 128);

	for(word_t idx = 128; idx < 256; idx++){
		b[idx] = (dlist_t *)malloc(sizeof(dlist_t));
		if(b[idx]) dlist_add_tail(&test_dlist, b[idx]);
	}
	assert(test_dlist.next == b[127]);
	assert(test_dlist.prev == b[255]);
	cnt = 0;
	for(dlist_t *node = test_dlist.next; node != &test_dlist; node = node->next){
		cnt++;
	}
	assert(cnt == 256);

	/* 测试删除 */
	__dlist_del(b[127]);
	free(b[127]);
	cnt = 0;
	for(dlist_t *node = test_dlist.prev; node != &test_dlist; node = node->prev){
		cnt++;
	}
	assert(cnt == 255);
	
}

/* 测试bitmap */
void test_bitmap(){
	size_t first_set;
	size_t popcnt = 0;
	DEF_SBITMAP(nbitmap, 1024);
	
	SBITMAP_ZERO_S(nbitmap, 1024);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 0);
	popcnt = SBITMAP_POPCOUNT_S(nbitmap, 1024);
	assert(popcnt == 0);
	
	SBITMAP_SET_S(nbitmap, 1);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 2);
	popcnt = SBITMAP_POPCOUNT_S(nbitmap, 1024);
	assert(popcnt == 1);

	bitmap_lshift(nbitmap, 1024, 2);
	assert(SBITMAP_FFS_S(nbitmap, 1024) == 4 && SBITMAP_POPCOUNT_S(nbitmap, 1024) == 1);

	/* 全填充 */
	SBITMAP_FILL_S(nbitmap, 1024);	
	/* 右移1024，应该为1 */
	bitmap_rshift(nbitmap, 1024, 1023);
	/* 找到第一个1，返回0 */
	assert(SBITMAP_FFS_S(nbitmap, 1024) == 1 && SBITMAP_POPCOUNT_S(nbitmap, 1024) == 1);
	/* 右移1024，应该全为0 */
	bitmap_rshift(nbitmap, 1024, 1);
	assert(SBITMAP_FFS_S(nbitmap, 1024) == 0);
	
	SBITMAP_SET_S(nbitmap, 63);
	SBITMAP_SET_S(nbitmap, 64);
	/* 右移1位 */
	bitmap_rshift(nbitmap, 1024, 1);
	assert(SBITMAP_FFS_S(nbitmap, 1024) == 63 && SBITMAP_POPCOUNT_S(nbitmap, 1024) == 2);

	/* 清零 */
	bitmap_lshift(nbitmap, 1024, 1023);

	DEF_SBITMAP(nbitmap_test, 256);
	SBITMAP_ZERO_S(nbitmap_test, 256);
	SBITMAP_SET_S(nbitmap_test, 4);
	assert(SBITMAP_FFS_S(nbitmap_test, 256) == 5 && SBITMAP_POPCOUNT_S(nbitmap_test, 256) == 1);
	bitmap_rshift(nbitmap_test, 256, 1000);
	assert(SBITMAP_FFS_S(nbitmap_test, 256) == 0 && SBITMAP_POPCOUNT_S(nbitmap_test, 256) == 0);

	nbitmap[(1024/BITS_PERSIZE) - 1] = 0x1UL << (BITS_PERSIZE - 1);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1024);

	bitmap_rshift(nbitmap, 1024, 1);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023);


	bitmap_rshift(nbitmap, 1024, 64);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64);
	
	bitmap_rshift(nbitmap, 1024, 129);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64 - 129);

	bitmap_rshift(nbitmap, 1024, 62);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64 - 129 - 62);

	bitmap_lshift(nbitmap, 1024, 62);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64 - 129);

	bitmap_lshift(nbitmap, 1024, 128);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64 - 1);

	bitmap_lshift(nbitmap, 1024, 1);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1023 - 64);

	bitmap_lshift(nbitmap, 1024, 65);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1024);
	
	bitmap_lshift(nbitmap, 1024, 1);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 0);
	
	/* 全填充 */
	SBITMAP_FILL_S(nbitmap, 1024);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 1);
	popcnt = SBITMAP_POPCOUNT_S(nbitmap, 1024);
	assert(popcnt == 1024);

	SBITMAP_ZERO_S(nbitmap, 1024);
	SBITMAP_SET_S(nbitmap, 511);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 512);
	popcnt = SBITMAP_POPCOUNT_S(nbitmap, 1024);
	assert(popcnt == 1);

	assert(SBITMAP_ISSET_S(nbitmap, 511));

	SBITMAP_CLR_S(nbitmap, 511);
	first_set = SBITMAP_FFS_S(nbitmap, 1024);
	assert(first_set == 0);
	popcnt = SBITMAP_POPCOUNT_S(nbitmap, 1024);
	assert(popcnt == 0);

	assert(!SBITMAP_ISSET_S(nbitmap, 511));
	/* -fanalyzer会报错 */
	/* SBITMAP_CLR_S(nbitmap, 1025); */

}

#include <dcont/pcorou.h>

#include <dcont/ptrampl.h>
// #include <habst.h>

static TLS_INITIAL prompt_t *cur_prompt;
static TLS_INITIAL presume_t root_prompt;
DEF_PROMPT_MODULE(cur_prompt, (prompt_t *)&root_prompt)

#define STACK_HEAP_INCR_ONCE_SIZE	(SIZE_1G)
#define STACK_HEAP_SLAB_SIZE		(SIZE_2M)

static TLS_INITIAL hstack_ctrl_t tmp_hstack;

DEF_HSTACK(tlsheapblk, 0, STACK_HEAP_INCR_ONCE_SIZE, STACK_HEAP_SLAB_SIZE, \
&tmp_hstack, page_alloc, page_free, mark_unused_pages)

DEF_COROU_ALLOC(tlsheapblk, tlsheapblk_hstack_get, tlsheapblk_hstack_ret, __corou_trampoline_yieldv)

DEF_HSTACK_SHARE(sheapblk, 0, STACK_HEAP_INCR_ONCE_SIZE, STACK_HEAP_SLAB_SIZE, \
&tmp_hstack, page_alloc, page_free, mark_unused_pages)

DEF_COROU_ALLOC(sheapblk, sheapblk_hstack_get, sheapblk_hstack_ret, __corou_trampoline_yieldv)

word_t cofun0(word_t arg){
	printf("cofun ready %lu\n", (ulong_t)arg);
	return arg + 1;
}
void test_hstack(){
	corou_t *p = tlsheapblk_corou_create(8192, cofun0, 0);
	assert(p);
	word_t ret;
	ret = corou_resume(p, 0);
	assert(ret == 1);
	// corou_reset(p);
	// ret = corou_resume(p, 1);
	// assert(ret == 2);
	tlsheapblk_corou_release(p);

	p = sheapblk_corou_create(8192, cofun0, 0);
	assert(p);
	ret = corou_resume(p, 0);
	assert(ret == 1);
	sheapblk_corou_release(p);
}   

int main(){

	test_radix();
	test_list();
	test_bitmap();

	test_hstack();
	printf("all test passed\n");
	return 0;
}

